<?php
/**
 * I-Cafe framework
 * 
 * @category CF
 * @package CF_Db
 * @link http://www.i-cafe.org
 * @license http://www.i-cafe.org/license
 * @version 04-04-2010
 * @author tcl_java@yahoo.com
 */

/**
 * Hander database connection
 * <code>
 * 	$dbConfig = array(
 * 		'host'		=> 'localhost',
 * 		'port'		=> 3306,
 * 		'username'	=> 'root',
 * 		'password'	=> 123
 * 	);
 * 	$connection = new CF_Db_Connection($dbConfig);
 * 	$connection->selectDb('mydb');
 * </code>
 */
class CF_Db_Connection extends CF_Component
{
	/**
	 * 
	 * @var string
	 */
	protected $_id;
	
	/**
	 * @var CF_Reader_Array
	 */
	protected $_config;
	
	/**
	 * @var Resource
	 */
	protected $_connection;
	
	/**
	 * 
	 * @param string $id
	 * @param CF_Storage_Array|array $config
	 * @return void
	 */
	public function __construct($id, $config = null)
	{
		$this->addEvents(
			'beforeconnect',
			'connect',
			'close',
			'selectdb'
		);
		
		$this->_id = (string) $id;
		
		if(is_array($config))
			$config = new CF_Storage_Array($config);
		
		if($config instanceof CF_Storage_Abstract)
			$this->connect($config);
	}
	
	/**
	 * @return string
	 */
	public function getId()
	{
		return $this->_id;
	}
	
	/**
	 * Load config database connection
	 * @param array $config
	 * @return void
	 * @throws CF_Db_Exception
	 */
	public function setConfig($config)
	{
		if(is_array($config)) $config = new CF_Storage_Array($config);
		
		if(!$config instanceof CF_Storage_Abstract){
			throw new CF_Db_Exception('Config option must be an array or CF_Reader_Array');
		}
		$this->_config = $config;
	}
	
	/**
	 * Get connection config
	 * @return array
	 */
	public function getConfig()
	{
		return $this->_config;
	}
	
	/**
	 * Magic method. Don't call this method
	 * @param string $name
	 * @param string $value
	 * @return void
	 */
	public function __set($name, $value)
	{
		$this->_config->set($name, $value);
	}
	
	/**
	 * Magic method. Don't call this method
	 * @param string $name
	 * @return mixed
	 */
	public function & __get($name)
	{
		return $this->_config->get($name);
	}
	
	/**
	 * Magic method. Don't call this method
	 * @param string $name
	 * @return boolean
	 */
	public function __isset($name)
	{
		return $this->_config->has($name);
	}
	
	/**
	 * Magic method. Don't call this method
	 * @param string $name
	 * @return void
	 */
	public function __unset($name)
	{
		$this->_config->remove($name);
	}
	
	/**
	 * 
	 * @param array $config [optional]
	 * @return Resource connection
	 */
	public function connect($config = null)
	{
		if($this->_connection) return $this->_connection;
		
		# notify before connect event
		if(CF_Observable::VALUE_RETURN === $this->fireEvent('beforeconnect', array($this))) return;
		
		if($config) $this->setConfig($config);
		
		$server = $this->_config->host . ':' . $this->_config->port;
		$this->_connection = @mysql_connect($server, $this->_config->username, $this->_config->password);
		if(false == $this->_connection){
			throw new CF_Db_Exception('Can not connect to database server');
		}
		
		# select db if dbname exist on config
		if($this->_config->dbname) $this->selectDb($this->_config->dbname);
		
		# set charset
		if($this->_config->charset) $this->setCharset($this->_config->charset);
		
		# notify connect event
		$this->fireEvent('connect', array($this));
		
		return $this->_connection;
	}
	
	/**
	 * Close connection
	 * @return boolean
	 */
	public function close()
	{
		$res = @mysql_close($this->getConnection());
		$this->_connection = null;
		
		# notify close event		
		$this->fireEvent('close', array($this, &$res));
		
		return $res;
	}
	
	/**
	 * Select a database
	 * @param string $dbName
	 * @return boolean
	 */
	public function selectDb($dbName)
	{
		$this->connect();
		$this->_config->dbname = $dbName;
		if(false == @mysql_select_db($dbName, $this->getConnection())){
			throw new CF_Db_Exception("Database \"$dbName\" does not exist");
		}
		
		# notify select database event
		$this->fireEvent('selectdb', array($this));
		
		return true;
	}
	
	public function setCharset($charset, $collation = null)
	{
		$charset = addslashes($charset);
		if(null !== $collation) $collation = addslashes($collation);
		$query = "SET NAMES $charset";
		$query .= $collation? "COLLATE $collation" : '';
		mysql_query($query, $this->getConnection());
	}
	
	/**
	 * Get database conection
	 * @return Resource
	 */
	public function getConnection()
	{
		return $this->connect();
	}
	
	/**
	 * Get error no
	 * @return int
	 */
	public function errno()
	{
		return @mysql_errno($this->getConnection());
	}
	
	/**
	 * Get error message
	 * @return string
	 */
	public function error()
	{
		return @mysql_error($this->getConnection());
	}
	
	/**
	 * Get error message with error no & error message
	 * @return 
	 */
	public function getError()
	{
		return $this->errno() . ':' . $this->error();
	}
	
	/**
	 * @return string
	 */
	public function __toString()
	{
		return $this->getId();
	}
}
